/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package avl.sv.shared.model.particleFeatureGenerator;

import avl.sv.shared.model.featureGenerator.AbstractFeatureGenerator;
import avl.testDouble.JOCL_FrangiFilter;
import ij.CompositeImage;
import ij.ImagePlus;
import ij.ImageStack;
import ij.Macro;
import ij.gui.Roi;
import ij.measure.Measurements;
import ij.measure.ResultsTable;
import ij.plugin.filter.Analyzer;
import ij.plugin.filter.ParticleAnalyzer;
import ij.process.ByteProcessor;
import ij.process.ImageProcessor;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;

/**
 *
 * @author benbryan
 */
public class FeatureGeneratorImageJ_Particle extends AbstractFeatureGenerator implements Serializable {
    public int measurements = 
        Measurements.AREA                |
        Measurements.MEAN                |
        Measurements.STD_DEV             |   
        Measurements.MODE                |
        Measurements.MIN_MAX             |
        Measurements.CENTROID            |
        Measurements.CENTER_OF_MASS      |
        Measurements.PERIMETER           |
        Measurements.LIMIT               |
        Measurements.RECT                |
        Measurements.LABELS              |
        Measurements.ELLIPSE             |  
        Measurements.CIRCULARITY         |       
        Measurements.SHAPE_DESCRIPTORS   |              
        Measurements.FERET               |   
        Measurements.INTEGRATED_DENSITY  |                 
        Measurements.MEDIAN              |                       
        Measurements.SKEWNESS            |       
        Measurements.KURTOSIS            |        
        Measurements.AREA_FRACTION       |              
        Measurements.SLICE               |     
        Measurements.STACK_POSITION      |               
        Measurements.SCIENTIFIC_NOTATION |                    
        Measurements.ADD_TO_OVERLAY      |              
        Measurements.MAX_STANDARDS       ;              

    public FeatureGeneratorImageJ_Particle() {
    }
        
    private static JOCL_FrangiFilter ff;

    static {
        ff = new JOCL_FrangiFilter();
    }
    private String[] featureNames;
    
    @Override
    public int getNumberOfFeatures() {
        return Integer.bitCount(measurements);
    }
    
    public double[] getFeaturesFromTable(ResultsTable rt) {
        int fSize = 100;
        double[] features = new double[fSize];
        int fIdx = 0;
        for (int i = 0; (i < rt.getLastColumn()) && (i < fSize); i++) {
            double[] data = rt.getColumnAsDoubles(i);
            if (data == null) {
                continue;
            }
            features[fIdx++] = data[0];
        }
        double[] out = new double[fIdx];
        System.arraycopy(features, 0, out, 0, fIdx);
        return out;
    }

    public ResultsTable generateResultsTable(BufferedImage img) {
        try {
            double sigmas[] = {2,4,6};
            BufferedImage outImage = ff.filter(img, sigmas);
            ByteProcessor mask = new ByteProcessor(outImage);

            Thread thread = Thread.currentThread();
            String name = thread.getName();
            if (!name.startsWith("Run$_")){
                    thread.setName("Run$_"+name);
            }
            Macro.setOptions("dummy");
            
            ResultsTable rt = new ResultsTable();
            double minSize = 0;
            double maxSize = Double.POSITIVE_INFINITY;
            double minCirc = 0;
            double maxCirc = 1;        
            ParticleAnalyzer pa = new ParticleAnalyzer(ParticleAnalyzer.SHOW_NONE, measurements, rt, minSize, maxSize, minCirc, maxCirc);
            
            ImagePlus imp = new ImagePlus("", img);       
            CompositeImage ci = new CompositeImage(imp, CompositeImage.COMPOSITE);
            
            String labels[] = ci.getStack().getSliceLabels();
            Object[] imgArray = ci.getStack().getImageArray();
            for (int i = 0; i < labels.length; i++){
                if ("Red".equals(labels[i])){
                    int width = imp.getWidth();
                    int height = imp.getHeight();
                    ImageStack stack = new ImageStack(width, height);
                    stack.addSlice("", imgArray[i]);    
                    ImagePlus impTemp = new ImagePlus("temp", stack);
                    Analyzer.setRedirectImage(impTemp);
                    mask.setRoi(imp.getRoi()==null?new Roi(0, 0, width, height):imp.getRoi());
                    mask.setThreshold(255, 255, ImageProcessor.NO_LUT_UPDATE);
                    pa.analyze(impTemp, mask);
                    return rt;
                }
            }
        } catch (Throwable ex) {
            Logger.getLogger(FeatureGeneratorImageJ_Particle.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }    

    @Override
    public String[] getFeatureNames() {
        return featureNames;
    }
    
    private void gatherFeatureNames(){
        // gather feature names
        ResultsTable rt = generateResultsTable(new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR));
        featureNames = new String[getNumberOfFeatures()];
        int fIdx = 0;
        for (int i = 0; (i < rt.getLastColumn()) && (i < getNumberOfFeatures()); i++) {
            double[] data = rt.getColumnAsDoubles(i);
            rt.getColumnHeading(i);
            if (data == null) {
                continue;
            }
            featureNames[fIdx++] = rt.getColumnHeading(i);
        }
    }

    @Override
    public String getName() {
        return "ImageJ_Particle";
    }    

    @Override
    public JPanel getOptionsPanel() {
        return new OptionsPromptImageJFeatures_Particle(this);
    }

    void setMeasurements(int measurements) {
        this.measurements = measurements;
        gatherFeatureNames();
    }

    int getMeasurements() {
        return measurements;
    }

    @Override
    public double[][] getFeaturesForImages(BufferedImage[] imgs) {
        double features[][] = new double[imgs.length][];
        for (int i = 0; i < imgs.length; i++){
            double temp[] = getFeaturesForImage(imgs[i]);
            features[i] = temp;
        }
        return features;
    }
    
    public double[] getFeaturesForImage(BufferedImage img) {
        ResultsTable rt = generateResultsTable(img);
        double[] features = getFeaturesFromTable(rt);
        return features;
    }

    @Override
    public void setFeatureNames(String[] names) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    
    
}
